package com.myalibaba.nacos;

import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingFactory;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.client.naming.NacosNamingService;
import com.myalibaba.nacos.bean.FeignUtil;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.web.client.RestTemplate;
import shade.fasterxml.jackson.databind.ObjectMapper;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.*;

/**
 * Nacos客户端API调用服务
 * Spring Cloud Alibaba 默认支持负载均衡。当多个实例注册到 Nacos 时，客户端可以通过服务名称调用多个实例，而 Spring Cloud 会根据负载均衡策略（如轮询、随机、权重等）选择一个实例进行调用。
 * 在 Spring Cloud Alibaba 中，服务发现的过程大致如下：
 * 微服务通过 spring-cloud-starter-alibaba-nacos-discovery 依赖与 Nacos 进行对接。
 * 服务在启动时注册到 Nacos 注册中心。
 * 其他微服务通过服务名称发现并调用已注册的服务。
 * Spring Cloud 提供了负载均衡的能力，使得调用端能够均衡地访问不同的服务实例。
 * 服务发现
 * Spring Cloud Alibaba 使用 Nacos 作为服务发现时，微服务并不会在启动时直接拉取所有服务列表。它只会根据需要查询服务注册表来发现服务实例。
 * 注册服务实例： 微服务会将自己注册到 Nacos 服务注册中心。
 * 查询服务实例： 当一个服务需要调用其他服务时，它会通过 Nacos 服务发现 API 查询服务列表，并获取具体的服务实例信息（如 IP 和端口）。这通常是通过 @LoadBalanced 或 @FeignClient 方式实现。
 * 例如，使用 Spring Cloud OpenFeign 配合 Nacos 服务发现时，微服务会在需要调用其他服务时，通过 Nacos 拉取服务实例。Nacos 会提供服务名对应的实例列表。
 */
public class NacosLocator {

    private static final String TEST_NACOS_SERVER_ADDR = "10.57.80.4:8848";
    private static final String SERVICE_NAME = "YIXIEKEJI-SHOP";
    private static final String TEST_NACOS_GROUP = "DEFAULT_GROUP";
    private static final String TEST_NACOS_DATA_ID = "YIXIEKEJI-MOBILE-WEB.yaml";
    private static final String TEST_NACOS_PASSWORD = "Nacos0829%$#&";

    @Test
    public void getAllInstances() {
        try {
            // 创建 Nacos 客户端连接属性
            Properties properties = new Properties();
            properties.put("serverAddr", TEST_NACOS_SERVER_ADDR);
            properties.put("username", "nacos");
            properties.put("password", TEST_NACOS_PASSWORD);
            properties.put("contextPath", "nacos");
            properties.put("namespace", "public");
            properties.put("fileExtension", "yaml");
            // 创建 NamingService 实例
            NamingService namingService = NamingFactory.createNamingService(properties);
            // 获取服务实例列表
            List<Instance> instances = namingService.getAllInstances(SERVICE_NAME);
            // 确保获取到实例
            if (instances.isEmpty()) {
                System.err.println("No instances found for service: " + SERVICE_NAME);
                return;
            }

            // 获取第一个实例
            Instance instance = instances.get(0);
            String serviceUrl = "http://" + instance.getIp() + ":" + instance.getPort() + "/code/getCodes";
            System.out.println("Service URL: " + serviceUrl);
            // 创建 FeignUtil 请求体对象
            FeignUtil feignUtil = new FeignUtil();
            Map<String, String> map = new HashMap();
            // 设置 FeignUtil 对象的属性（根据接口需要填充）
            map.put("q_codeDiv", "ACTION_TYPE");
            feignUtil.setQueryMap(map);
            // 调用服务，传递 JSON 请求体
            String response = callService(serviceUrl, "POST", feignUtil);  // 传递 POST 请求和 FeignUtil 对象
            System.out.println("服务响应:\n " + response);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static String callService(String serviceUrl, String method, FeignUtil feignUtil) throws IOException {
        // 创建 URL 对象
        URL url = new URL(serviceUrl);
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();

        // 设置请求方法为 POST（或其他）
        connection.setRequestMethod(method);  // POST 或 GET 根据接口要求

        // 设置请求头部，Content-Type 为 application/json
        connection.setRequestProperty("Content-Type", "application/json");

        // 设置 Basic Authentication 请求头
        String username = "nacos";
        String password = "Nacos0829%$#&";
        String auth = username + ":" + password;
        String encodedAuth = Base64.getEncoder().encodeToString(auth.getBytes("UTF-8"));
        connection.setRequestProperty("Authorization", "Basic " + encodedAuth);

        // 将 FeignUtil 对象序列化为 JSON
        ObjectMapper objectMapper = new ObjectMapper();
        String jsonRequestBody = objectMapper.writeValueAsString(feignUtil);

        // 设置请求体
        connection.setDoOutput(true);
        try (OutputStream os = connection.getOutputStream()) {
            byte[] input = jsonRequestBody.getBytes("utf-8");
            os.write(input, 0, input.length);  // 将请求体写入连接
        }

        // 发送请求并获取响应
        int responseCode = connection.getResponseCode();
        if (responseCode == HttpURLConnection.HTTP_OK) {
            BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
            StringBuilder response = new StringBuilder();
            String inputLine;
            while ((inputLine = in.readLine()) != null) {
                response.append(inputLine);
            }
            in.close();
            return response.toString();
        } else {
            throw new IOException("Service returned non-OK response: " + responseCode);
        }
    }


    // 获取配置并直接输出为字符串
    @Test
    public void getNaocsConfig() {
        try {
            Properties properties = new Properties();
            properties.put("serverAddr", TEST_NACOS_SERVER_ADDR);
            properties.put("username", "nacos");
            properties.put("password", TEST_NACOS_PASSWORD);
            properties.put("contextPath", "nacos");
            properties.put("namespace", "public"); // 确认namespace是否正确
            properties.put("fileExtension", "yaml");

            // 打印调试信息
            System.out.println("Connecting to Nacos server at: " + TEST_NACOS_SERVER_ADDR);

            ConfigService configService = NacosFactory.createConfigService(properties);
            String content = configService.getConfig(TEST_NACOS_DATA_ID, TEST_NACOS_GROUP, 5000);

            // 输出调试信息
            if (content == null) {
                System.out.println("Failed to get config: " + TEST_NACOS_DATA_ID);
            } else {
                System.out.println("Config Content: " + content);
            }
        } catch (NacosException e) {
            System.out.println("NacosException occurred: " + e.getMessage());
            e.printStackTrace();
        }
    }

    // 获取健康或不健康实例列表
    @Test
    public void selectInstances() {
        try {
            NamingService naming = NamingFactory.createNamingService(TEST_NACOS_SERVER_ADDR);
            System.out.println(naming.selectInstances(SERVICE_NAME, true));
        } catch (NacosException e) {
            e.printStackTrace();
        }
    }

    // 获取健康或不健康实例列表
    @Test
    public void selectOneHealthyInstance() {
        try {
            NamingService naming = NamingFactory.createNamingService(TEST_NACOS_SERVER_ADDR);
            System.out.println(naming.selectOneHealthyInstance(SERVICE_NAME));
        } catch (NacosException e) {
            e.printStackTrace();
        }
    }


    /**
     * 通过 Nacos HTTP API 获取服务实例数量
     * 使用以下命令查看注册的服务实例：
     * curl -X GET "http://10.57.80.4:8848/nacos/v1/ns/catalog/services?namespaceId=public&serviceName=YIXIEKEJI-SHOP" -u nacos:Nacos0829%24%23%26
     * URL 编码： 如果密码中包含特殊字符（如 &, %, $ 等），需要确保它们被 URL 编码。特别是 & 需要用 %26 替代。你可以尝试将密码中的特殊字符进行 URL 编码：
     * & 替换为 %26
     * $ 替换为 %24
     * # 替换为 %23
     *
     */
    @Test
    public void getServiceInstanceCount() {
        RestTemplate restTemplate = new RestTemplate();
        String url = "http://" + TEST_NACOS_SERVER_ADDR + "/nacos/v1/ns/catalog/services?namespaceId=public&serviceName=" + SERVICE_NAME;
        // 如果需要身份验证，可以设置 HTTP 头
        HttpHeaders headers = new HttpHeaders();
        headers.setBasicAuth("nacos", TEST_NACOS_PASSWORD);
        HttpEntity<String> entity = new HttpEntity<>(headers);
        String response = restTemplate.getForObject(url, String.class);  // 发送 GET 请求
        // 解析返回的 JSON 响应
        // 这里假设返回的 JSON 格式类似于 {"serviceName": "YIXIEKEJI-SHOP", "hosts": [...]}，你可以使用 JSON 解析库（如 Jackson 或 Gson）来解析
        int instanceCount = response.split("\"hosts\":").length - 1;
        System.out.println("服务数量：" + instanceCount);
    }


    /**
     * 使用 Spring Cloud Nacos 提供的 DiscoveryClient获取服务实例数量
     */
/*    @Autowired
    private DiscoveryClient discoveryClient;
    public int getServiceInstanceCount(String serviceName) {
        List<ServiceInstance> instances = discoveryClient.getInstances(serviceName);
        return instances.size();
    }*/


}
